with MIDI.Control_Events, MIDI.Meta_Events;
with Ada.Containers; use Ada.Containers;
with Ada.Containers.Indefinite_Doubly_Linked_Lists;
package MIDI.Events is

   subtype Note_Off            is Uint8_t range 16#80# .. 16#8F#;
   subtype Note_On             is Uint8_t range 16#90# .. 16#9F#;
   subtype Key_After_Touch     is Uint8_t range 16#A0# .. 16#AF#;
   subtype Controller_Change   is Uint8_t range 16#B0# .. 16#BF#;
   subtype Program_Change      is Uint8_t range 16#C0# .. 16#CF#;
   subtype Channel_After_Touch is Uint8_t range 16#D0# .. 16#DF#;
   subtype Pitch_Wheel_Change  is Uint8_t range 16#E0# .. 16#EF#;
   subtype Control             is Uint8_t range 16#80# .. 16#EF#;
   subtype SysEx_Normal        is Uint8_t range 16#F0# .. 16#F0#;
   subtype SysEx_Divided       is Uint8_t range 16#F7# .. 16#F7#;
   subtype Timing_Clock_Used   is Uint8_t range 16#F8# .. 16#F8#;
   subtype Start_Sequence      is Uint8_t range 16#FA# .. 16#FA#;
   subtype Continue_Sequence   is Uint8_t range 16#FB# .. 16#FB#;
   subtype Stop_Sequence       is Uint8_t range 16#FC# .. 16#FC#;
   subtype Meta                is Uint8_t range 16#FF# .. 16#FF#;
   subtype Unspecified         is Uint8_t range 16#00# .. 16#7F#;

   type Midi_Event_Type (Token : Uint8_t) is record
      case Token is
         when Note_Off            => As_Note_Off            : Control_Events.Note_Off_Event;
         when Note_On             => As_Note_On             : Control_Events.Note_On_Event;
         when Key_After_Touch     => As_Key_After_Touch     : Control_Events.Key_After_Touch_Event;
         when Controller_Change   => As_Controller_Change   : Control_Events.Controller_Change_Event;
         when Program_Change      => As_Program_Change      : Control_Events.Program_Change_Event;
         when Channel_After_Touch => As_Channel_After_Touch : Control_Events.Channel_After_Touch_Event;
         when Pitch_Wheel_Change  => As_Pitch_Wheel_Change  : Control_Events.Pitch_Wheel_Change_Event;
         when SysEx_Normal | SysEx_Divided => As_SysEx_Size : Uint32_vl;
         when Meta                => As_Meta_Head           : Meta_Events.Meta_Event_Head_Type;
         when Timing_Clock_Used   => null;
         when Start_Sequence | Stop_Sequence | Continue_Sequence => null;
         when Unspecified         => null;
         when others              => null;
      end case;
   end record;

   type Track_Event (Token : Uint8_t; Size : Natural) is record
      At_Time      : Uint32_vl;
      Event        : Midi_Event_Type(Token);
      Data         : String(1..Size);
   end record;

   function "<" (
      E1, E2 : Track_Event
      ) return Boolean is (E1.At_Time < E2.At_Time);

   package Event_Lists is
      new Indefinite_Doubly_Linked_Lists(Events.Track_Event);

   package Event_Lists_Sorting is
      new Event_Lists.Generic_Sorting;
   
end MIDI.Events;
